#ifndef __UART_H__
#define __UART_H__
#ifdef __cplusplus
extern "C"
{
#endif
        /****************************************************************/
        /*
            STC8、15系列keil串口库 By 启凡科创。
            Version:2.0.2 2023-2-16

            串口固定工作在8N1的模式，暂不适配其他模式
            使用串口前请将TXD对应GPIO设置为双向口或推挽输出模式，RXD设置为INPUT或双向口
            如需printf格式化输出，需配合重定向使用实现

        */
        /****************************************************************/

#include "LIB_CONFIG.h"
#include "STRING.H"

// 如果配置文件未使能，则可更改此参数用户自定义，0禁用模块不不编译，1启用模块
#ifndef UART1_EN
#define UART1_EN 0 // 串口1
#endif
#ifndef UART2_EN
#define UART2_EN 0 // 串口2
#endif
#ifndef UART3_EN
#define UART3_EN 0 // 串口3
#endif
#ifndef UART4_EN
#define UART4_EN 0 // 串口4
#endif

#if ( UART1_EN ||  UART2_EN ||  UART3_EN ||  UART4_EN)

#define UART1_TXD_BUFFER_SIZE 1  // 串口1发送FIFO缓冲大小,至少为1，如果缓存小于要发送的数据长度，将阻塞至发送结束，如果缓存足够则为queue中断自动传输
#define UART2_TXD_BUFFER_SIZE 32 // 串口2发送FIFO缓冲大小,至少为1，如果缓存小于要发送的数据长度，将阻塞至发送结束，如果缓存足够则为queue中断自动传输
#define UART3_TXD_BUFFER_SIZE 32 // 串口3发送FIFO缓冲大小,至少为1，如果缓存小于要发送的数据长度，将阻塞至发送结束，如果缓存足够则为queue中断自动传输
#define UART4_TXD_BUFFER_SIZE 32 // 串口4发送FIFO缓冲大小,至少为1，如果缓存小于要发送的数据长度，将阻塞至发送结束，如果缓存足够则为queue中断自动传输

#define UART1_RXD_BUFFER_SIZE 9  // 串口1接收FIFO缓冲大小,为0则关闭接收功能
#define UART2_RXD_BUFFER_SIZE 16 // 串口2接收FIFO缓冲大小,为0则关闭接收功能
#define UART3_RXD_BUFFER_SIZE 16 // 串口3接收FIFO缓冲大小,为0则关闭接收功能
#define UART4_RXD_BUFFER_SIZE 16 // 串口4接收FIFO缓冲大小,为0则关闭接收功能

        typedef enum
        {
#ifdef UART1_EN
                uart1,
#endif
#ifdef UART2_EN
                uart2,
#endif
#ifdef UART3_EN
                uart3,
#endif
#ifdef UART4_EN
                uart4,
#endif
                UART_USE_NUM_MAX
        } UART_TYPE; // 启用的串口编号，如未启用将无法调用

        typedef enum
        {
#ifdef UART1_EN
                timer1, // 定时器1
#endif
                timer2, // 定时器2
#ifdef UART3_EN
                timer3, // 定时器3
#endif
#ifdef UART4_EN
                timer4 // 定时器4
#endif
        } timer_type; // 用作为波特率发生器的定时器

        typedef enum
        {
                uart_gpio_1, // 输出GPIO组为1
                uart_gpio_2, // 输出GPIO组为2
                uart_gpio_3, // 输出GPIO组为3
                uart_gpio_4, // 输出GPIO组为4
        } UART_GPIO_NUM;

        /**
         * @brief 配置串口参数，初始化串口
         *
         * @param uart_num 串口编号:
         * @param ··uart1 支持timer1、2
         * @param ··uart2 支持timer2
         * @param ··uart3 支持timer2、3
         * @param ··uart4 支持timer2、4
         * @param --
         * @param timer 用作为波特率发生器的定时器:
         * @param ··timer1 启用UART1时可见
         * @param ··timer2 启用任意串口时可见
         * @param ··timer3 启用UART3时可见
         * @param ··timer4 启用UART4时可见
         * @param --
         * @param cpu_frq CPU工作主频,如工作在24M时为24000000
         * @param --
         * @param band 波特率,如115200,过高的波特率可能在某些系统时钟下配置成功但数据乱码
         * @param --
         * @param return uint8_t 返回代码对应如下：
         * @param ··0 配置成功
         * @param ··1 当前要配置的串口已经在工作，要重新配置需先end后再进行配置
         * @param ··2 当前给的系统工作时钟参数无法产生对应波特率或波特率参数不合规
         * @param ··3 选用的timer不可作为对应串口的波特率发生器
         */
        uint8_t serial_begin(UART_TYPE uart_num, timer_type timer, unsigned long cpu_frq, unsigned long band);

        /**
         * @brief 关闭指定的串口，如果串口还在发送任务中则会等待发送结束后关闭
         *
         * @param uart_num 串口编号:
         * @param ··uart1
         * @param ··uart2
         * @param ··uart3
         * @param ··uart4
         */
        void serial_end(UART_TYPE uart_num);

        /**
         * @brief 切换指定串口的输出GPIO组号
         *
         * @param uart_num 串口编号:
         * @param ··uart1
         * @param ··uart2
         * @param ··uart3
         * @param ··uart4
         * @param --
         * @param num GPIO输出组号：
         * @param ··uart_gpio_1 输出GPIO组为1
         * @param ··uart_gpio_2 输出GPIO组为2
         * @param ··uart_gpio_3 输出GPIO组为3
         * @param ··uart_gpio_4 输出GPIO组为4
         */
        void serial_switch_output_gpio(UART_TYPE uart_num, UART_GPIO_NUM num);

        /**
         * @brief 返回接收缓冲区还有多少字节数据
         *
         * @param uart_num 串口编号:
         * @param u··uart1
         * @param ··uart2
         * @param ··uart3
         * @param ··uart4
         * @return unsigned short
         */
        unsigned short serial_available(UART_TYPE uart_num);

        /**
         * @brief 缓冲区读取一个字节
         *
         * @param uart_num 串口编号:
         * @param ··uart1
         * @param ··uart2
         * @param ··uart3
         * @param ··uart4
         * @return uint8_t
         */
        uint8_t serial_read(UART_TYPE uart_num);

        /**
         * @brief 返回发送缓冲区还有多少字节待发送中
         *
         * @param uart_num 串口编号:
         * @param ··uart1
         * @param ··uart2
         * @param ··uart3
         * @param ··uart4
         * @return uint16_t
         */
        uint16_t serial_chek_busy(UART_TYPE uart_num);

        /**
         * @brief 发送一个字节
         *
         * @param uart_num 串口编号:
         * @param ··uart1
         * @param ··uart2
         * @param ··uart3
         * @param ··uart4
         * @param dat
         */
        void serial_write(UART_TYPE uart_num, uint8_t dat);

        /**
         * @brief 发送指定长度字节，发送后CPU会自己中断性质循环发送直到发完，可用serial_chek_busy函数查询排队剩余字节
         *
         * @param uart_num 串口编号:
         * @param ··uart1
         * @param ··uart2
         * @param ··uart3
         * @param ··uart4
         * @param --
         * @param dat 指向发送的数据
         * @param --
         * @param size 发送的长度
         */
        void serial_write_bytes(UART_TYPE uart_num, uint8_t *dat, uint16_t size);

#if (UART1_RXD_BUFFER_SIZE || UART2_RXD_BUFFER_SIZE || UART3_RXD_BUFFER_SIZE || UART4_RXD_BUFFER_SIZE)
        /**
         * @brief 设置接收缓存位置,默认放于内置的缓存内，如需将接收数据直接放到指定缓存可使用此接口更改,此操作将清空原缓存已经接收的数据
         *
         * @param uart_num
         * @param ··uart1
         * @param ··uart2
         * @param ··uart3
         * @param ··uart4
         * @param --
         * @param buffer 指定的缓存区域，大小需要同头文件内配置的RXD接收缓存大小一致或更大，否则会导致死机，为NULL则改回默认内部缓存
         * @param --
         * @param size 缓存大小，错误的大小会导致崩溃
         */
        void serial_set_rec_buffer(UART_TYPE uart_num, uint8_t *buffer, size_t size);
#endif

#endif
#ifdef __cplusplus
}
#endif
#endif
